<?php

namespace App\Http\Handler;

use App\Constants\Common\HttpStatusCode;
use Framework\Foundation\Response\ResponseGen;
use Framework\MiddlewareRunner;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use App\Foundation\Utils\JwtAssistant;

class JsonWebTokenHandler implements RequestHandlerInterface
{
    protected $key;
    protected $mustAuth = true;

    public function __construct($key, $mustAuth = true)
    {
        $this->key = $key;
        $this->mustAuth = $mustAuth;
    }


    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        try {
            $tokenStr = $this->getToken($request);
            if (!empty($tokenStr)) {
                $tokenInfo = $this->parseToken($tokenStr);

                if (false !== $tokenInfo) {
                    $request = $request->withAttribute('jwtToken', $tokenInfo);
                    if ($tokenInfo->hasClaim('uid')) {
                        $request = $request->withAttribute('member_id', $tokenInfo->getClaim('uid'));
                    }
                }
            }
        } catch (\Exception $e) {
            return ResponseGen::error($e->getCode(), $e->getMessage());
        }

        return MiddlewareRunner::next($request);
    }

    public function getToken(ServerRequestInterface $request)
    {
        $cookies = $request->getCookieParams();
        $authToken = $cookies['Authorization'] ?? null;
        if (is_null($authToken)) {
            $authToken = $request->getHeader('Authorization');
            if (is_array($authToken)) {
                $authToken = $authToken[0];
            }
        }

        $tokenStr = str_replace(['Bearer ', 'Bearer'], '', $authToken);
        if ('undefined' == $tokenStr) {
            $tokenStr = '';
        }

        if (empty($tokenStr) && $this->mustAuth) {
            throw new \Exception("缺失认证token，您需要先登录", HttpStatusCode::UNAUTHORIZED);
        }

        return $tokenStr;
    }

    public function parseToken(string $tokenStr)
    {
        $jtw = new JwtAssistant($this->key);
        $tokenInfo = $jtw->verifyToken($tokenStr, $this->key);

        if ($this->mustAuth && false === $tokenInfo) {
            throw  new \Exception("权限认证未通过, 您需要先登录", HttpStatusCode::UNAUTHORIZED);
        }

        if (false !== $tokenInfo && $this->mustAuth && $tokenInfo->isExpired()) {
            throw  new \Exception("token已过期,您需要重新登录", HttpStatusCode::UNAUTHORIZED);
        }

        return $tokenInfo;
    }
}
